package com.study.demo01.web;

import cn.hutool.core.date.DateUtil;
import com.study.demo01.config.DelayedExchangeConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Date;

@Slf4j
@RestController
@RequestMapping("/ttl")
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class SendController {

    private final RabbitTemplate rabbitTemplate;


    @GetMapping("/sendMsg/{msg}")
    public void sendMsg(@PathVariable("msg") String msg) {
        log.info("发送消息[{}]", msg);

        rabbitTemplate.convertAndSend("X", "XA", "来自ttl10的消息" + msg);
        rabbitTemplate.convertAndSend("X", "XB", String.format("来自ttl40的消息%s", msg));

    }

    /**
     * 在属性上设置TTL的方式，消息可能不会按时死亡，因为rabbitmq只会检查第一个消息是否过期，如果过期丢到死信队列，如果第一个消息的延时时间很长，
     * 而第二个延时时间很短，第二个消息并不会优先得到执行。
     */
    @GetMapping("/sendMsgttl/{msg}/{ttlTime}")
    public void sendMsgttl(@PathVariable("msg") String msg, @PathVariable String ttlTime) {
        log.info("发送消息[{}]-延时时间[{}]", msg, ttlTime);
        rabbitTemplate.convertAndSend("X", "XC", String.format("来自ttl %s的消息%s", ttlTime, msg), msgPostProcessor -> {
            msgPostProcessor.getMessageProperties().setExpiration(ttlTime);
            return msgPostProcessor;
        });


    }

    /**
     * systemctl status rabbitmq-server
     */
    //基于插件的延迟队列
    @GetMapping("/sendDealyMsg/{msg}/{ttlTime}")
    public void sendDelayedMsgttl(@PathVariable("msg") String msg, @PathVariable Integer ttlTime) {
        long l = Duration.ofSeconds(ttlTime).toMillis();

        log.info("发送消息[{}]-延时时间[{}--{}]", msg, DateUtil.now(), l);
        LocalDateTime localDateTime = DateUtil.toLocalDateTime(new Date());

        rabbitTemplate.convertAndSend(DelayedExchangeConfig.delayed_exchange_name, DelayedExchangeConfig.delayed_routing_key, String.format("来自延迟交换机 %s的消息%s", ttlTime, msg), msgPostProcessor -> {

            msgPostProcessor.getMessageProperties().setDelay((int) l);
            return msgPostProcessor;
        });
    }
    /**
     *延迟队列在需要延时处理的场景非常有用，使用rabbitmq来实现延时队列可用很好的利用rabbitmq的特性，如：消息可靠发送，消息可靠投递，
     * 死信队列来保障消息至少被消费一次以及未被真确处理的消息不会被丢弃，另外通过rabbitmq集群的特性，可用很好的解决单点故障的问题，不会因为单个节点导致队列不可用或消息丢失。
     * <br/>
     * 当然，延时队列还有很多其他选择，比如Java的DelayQueue，利用Redis的zset,利用Quartz或者利用kafka的时间轮，这些方式各有特点，看需要适用的场景。
     */
}
